package com.hzw.saas.web.sso.controller.sso;

import com.hzw.saas.common.config.annotation.SysLog;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.RedisUtil;
import com.hzw.saas.web.sso.controller.request.CodeRequest;
import com.hzw.saas.web.sso.controller.request.PasswordRequest;
import com.hzw.saas.web.sso.controller.request.RefreshTokenRequest;
import com.hzw.saas.web.sso.exception.SaasOauthException;
import com.hzw.saas.web.sso.pojo.dto.TokenInfoDto;
import com.hzw.saas.web.sso.pojo.model.SaasClient;
import com.hzw.saas.web.sso.service.ISaasClientService;
import com.hzw.saas.web.sso.service.ISaasOauthService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiOperationSort;
import io.swagger.annotations.ApiSort;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Objects;
import java.util.Set;

/**
 * <p>
 * 第三方授权接口
 * </p>
 * 1、申请APPID。
 * 2、登录模式方式为授权码模式登录（调用/authorize）获取授权码。
 * 3、在后台通过授权码(授权码模式)拿到access_token，这样就可以访问saas后台接口。
 * 4、如果access_token快过期了，则调用刷新token模式，刷新access_token，或者重新授权。
 *
 * @author sonam
 * @since 2021/3/1 9:38
 */
@Slf4j
@RestController
@ApiSort(value = 2)
@RequiredArgsConstructor
@Api(tags = "鸿之微/OAuth2认证外部接口")
@RequestMapping("/saas/oauth2")
public class Oauth2Controller {
    private final ISaasOauthService oauthService;
    private final ISaasClientService saasClientService;

    @ApiOperationSort(3)
    @PostMapping(value = "/access")
    @SysLog(operation = "获取access token")
    @ApiOperation(value = "使用授权码获取业务token", notes = "使用授权码获取业务token（access token），授权码通过访问认证中心前端获取")
    public ResponseEntity<TokenInfoDto> accessToken(CodeRequest codeRequest) throws SaasOauthException {
        return ResponseEntity.ok(oauthService.getTokenByCode(getClient(codeRequest.getClient_id()), codeRequest.getClient_secret(), codeRequest.getCode()));
    }

    @ApiOperationSort(4)
    @PostMapping(value = "/refresh")
    @SysLog(operation = "续期access token")
    @ApiOperation(value = "续期access token", notes = "续期access token")
    public ResponseEntity<TokenInfoDto> refreshToken(RefreshTokenRequest request) throws SaasOauthException {
        return ResponseEntity.ok(oauthService.refreshToken(getClient(request.getClient_id()), request.getRefresh_token()));
    }

//    @SysLog(operation = "密码模式登录")
//    @PostMapping(value = "/password")
//    @ApiOperation(value = "密码模式直接获取授权码", notes = "密码模式 /saas/oauth2/password?grant_type=password&client_id=&username=&password=")
//    @ApiOperationSort(4)
    public ResponseEntity<TokenInfoDto> password(@Validated PasswordRequest request) throws SaasOauthException {
        return ResponseEntity.ok(oauthService.password(getClient(request.getClient_id()), request.getClient_id(), request.getUsername(), request.getPassword()));
    }

    @SysLog(operation = "删除所有登录token")
    @DeleteMapping(value = "/clear")
    @ApiOperation(value = "删除所有登录token（仅测试用）", notes = "删除所有登录token（仅测试用）")
    @ApiOperationSort(4)
    public ResponseEntity<String> clear() {
        Set<String> tokenKeys =  RedisUtil.keys("SSO:TOKEN*");
        for (String tokenKey : tokenKeys) {
            RedisUtil.del(tokenKey);
        }
        return ResponseEntity.ok().build();
    }

    private SaasClient getClient(String clientId) {
        SaasClient client = saasClientService.getById(clientId);
        AssertUtil.assertThrow("客户端client_id不存在", Objects.isNull(client));
        return client;
    }

}
